package com.yuanfengPlus.utils;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class ExcelImportUtil {

    /**
     * 使用EasyExcel进行文件导入的通用工具方法
     *
     * @param file          要导入的MultipartFile类型文件
     * @param clazz         Excel数据对应的实体类类型
     * @param listener      自定义的监听器，用于处理每行数据以及整体解析完成后的操作
     * @return 解析后的数据列表，如果导入过程中出现错误，返回的列表可能为空
     */
    public static <T, L extends AnalysisEventListener<T> & HasDataList<T>> List<T> importExcel(MultipartFile file, Class<T> clazz, L listener) {
        if (file == null || file.isEmpty()) {
            log.error("导入文件为空");
            return new ArrayList<>();
        }
        try {
            EasyExcel.read(file.getInputStream(), clazz, listener).sheet().doRead();
            return listener.getDataList();
        } catch (IOException e) {
            log.error("文件导入过程中发生IO异常: ", e);
        } catch (Exception e) {
            log.error("文件导入过程中发生其他异常: ", e);
        }

        return new ArrayList<>();
    }

    /**
     * 示例监听器，可根据具体业务需求继承该监听器并重写相应方法进行定制化处理
     *
     * @param <T> 数据对应的实体类类型
     */
    public static abstract class AbstractExcelListener<T> extends AnalysisEventListener<T> implements HasDataList<T> {

        private List<T> dataList = new ArrayList<>();

        @Override
        public void invoke(T t, AnalysisContext analysisContext) {
            // 可在这里对每行数据进行通用的校验等操作，如非空校验等
            if (t == null) {
                log.error("第{}行数据为空", analysisContext.readRowHolder().getRowIndex() + 1);
                return;
            }
            dataList.add(t);
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
            // 所有数据解析完成后，可在这里进行通用的后续操作，如打印导入数据数量等
            log.info("共导入{}条数据", dataList.size());
        }

        @Override
        public List<T> getDataList() {
            return dataList;
        }
    }

    /**
     * 定义一个接口，确保监听器实现此接口以提供获取数据列表的方法
     *
     * @param <T> 数据对应的实体类类型
     */
    public interface HasDataList<T> {
        List<T> getDataList();
    }
}